package com.ruoyi.oauth.sso;

import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oauth.domain.OauthToken;
import com.ruoyi.oauth.sso.service.IOauthService;
import com.ruoyi.oauth.sso.service.OauthLoginService;
import com.ruoyi.oauth.sso.vo.OAuthCode;
import com.ruoyi.oauth.sso.vo.OAuthRequest;
import com.ruoyi.oauth.utils.OAuthUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * @author yepanpan
 * @date 2024/1/11 11:42
 */
@Controller
@RequestMapping("/oauth2")
public class AuthorizeController {
    private static final Logger log = LoggerFactory.getLogger(AuthorizeController.class);
    private String prefix = "oauth/";
    @Autowired
    IOauthService oauthService;
    @Autowired
    OauthLoginService oauthLoginService;

    /**
     * 进入登录页面,如果已登录，直接跳转
     *
     * @param model
     * @param request
     * @return
     * @throws URISyntaxException
     */
    @GetMapping("/authorize")
    public Object authorize(Model model, HttpServletRequest request){
        OAuthRequest oauthRequest = null;
        Object ret = null;
        String state = "0";
        try {
            oauthRequest = new OAuthRequest(request);
            if (oauthLoginService.checkLogin(request)) {
                log.debug("当前用户已登录，直接返回code");
                oauthRequest.setAccessToken(request.getSession().getAttribute("token").toString());
                ret =  buildCodeResponse(oauthRequest);
            }else if (oauthService.checkClient(model, oauthRequest.getClientId()) != null) {
                log.debug("当前用户未登录，进入登录页面");
                oauthService.getLogin(model, oauthRequest);
                ret = prefix + "authorize";
            }else{
                state = "1";
                throw new ServiceException("不支持客户端");
            }

        }catch (Exception e){
            log.error("进入单点登录页面时，发生错误: {}", e);
            ret = new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        //记录日志
        oauthService.log(oauthRequest.getClientId(), null, "单点登录页面",
                request.getRemoteHost(), null, request.getQueryString(), state);

        return ret;
    }

    /**
     * 登录验证后跳转
     *
     * @param model
     * @param request
     * @return
     * @throws URISyntaxException
     */
    @PostMapping("/authorize")
    public Object login(Model model, HttpServletRequest request){
        OAuthRequest oauthRequest = null;
        Object ret = null;
        String state = "0";
        try {
            oauthRequest = new OAuthRequest(request);
            if (oauthLoginService.checkLogin(request)) {
                log.debug("当前用户已登录，直接返回code");
                oauthRequest.setAccessToken(request.getSession().getAttribute("token").toString());
                ret = buildCodeResponse(oauthRequest);
            } else if (oauthService.checkClient(model, oauthRequest.getClientId()) != null) {
                log.debug("进行登录验证");
                String token = oauthLoginService.login(request);
                log.debug("登录成功，token {}", token);
                request.getSession().setAttribute("token", token);
                log.debug("进入中转页面");
                oauthService.getLogin(model, oauthRequest);
                //登录成功时跳转到临时页面，保持在本系统已登录
                ret = prefix + "code";

            }else{
                state = "1";
                throw new ServiceException("不支持客户端");
            }

        }catch (Exception e){
            log.error("单点登录验证账号密码错误: {}", e);
            ret = new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }

        //记录日志
        oauthService.log(oauthRequest.getClientId(), null, "单点登录验证",
                request.getRemoteHost(), null, request.getQueryString(), state);
        return ret;
    }

    /**
     * 构建回跳的响应对象
     * @param request
     * @param token
     * @return
     * @throws URISyntaxException
     */
    private ResponseEntity<Object> buildCodeResponse(OAuthRequest request) throws URISyntaxException {
        OAuthCode code = oauthService.buildCode(request);
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(new URI(OAuthUtil.buildCodeResponse(request, code)));
        return new ResponseEntity<>(headers, HttpStatus.MOVED_TEMPORARILY);
    }

    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */
    @GetMapping("/logout")
    public void logout(HttpServletRequest request, HttpServletResponse response) {


        //跳转
        String redirectUri = request.getParameter("redirect_uri");
        if(StringUtils.isEmpty(redirectUri)){
            redirectUri = request.getContextPath()+"/login";
        }
        try {
            OauthToken oauthToken = oauthService.checkToken(request);
            if(oauthToken != null){
                //记录日志
                oauthService.log(oauthToken.getClientId(), oauthToken.getUserName(), "退出",
                        request.getRemoteHost(), oauthToken.getAccessToken(), request.getQueryString(), "0");

                oauthLoginService.logout(oauthToken);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try{
                request.getSession().invalidate();
                response.sendRedirect(redirectUri);
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    }
}
